package ch.bfh.mgb.hamilton.statistics;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import ch.bfh.mgb.hamilton.entities.Robot;
import ch.bfh.mgb.hamilton.simulation.SimulationParameters;

public class Statistics {
	private List<GenerationDTO> generations;
	private int minPop;
	private long maxPop;
	private int infiniteCounter;
	private int popCount;
	
	
	public Statistics() {
		infiniteCounter = - (SimulationParameters.iterations - 1);
		popCount = 1;
	}
	
	public void init(List<Robot> initPop) {
		GenerationDTO dto = new GenerationDTO();
		dto.generationNumber = 0;
		maxPop = initPop.size();
		minPop = initPop.size();
		dto.robots = new ArrayList<Robot>(initPop);
		Collections.copy(dto.robots, initPop);
		dto.livingRobots = dto.robots.size();
		dto.overagedRobots = 0;
		dto.starvedRobots = 0;
		dto.newChildren = 0;

		generations = new ArrayList<GenerationDTO>();
		generations.add(dto);
	}
	
	public void processStatistics(int round, List<Robot> actGen, int starvedRobots, int overagedRobots, int newChildren) {
		GenerationDTO dto = new GenerationDTO();
		dto.generationNumber = round;
		
		if (actGen.size() > maxPop) {
			maxPop = actGen.size();
		} else if (actGen.size() < minPop) {
			minPop = actGen.size();
		}

		if (!SimulationParameters.infiniteGenerations) {
			dto.robots = new ArrayList<Robot>(actGen);
			Collections.copy(dto.robots, actGen);
			dto.livingRobots = dto.robots.size();
			dto.overagedRobots = overagedRobots;
			dto.starvedRobots = starvedRobots;
			dto.newChildren = newChildren;
			generations.add(dto);
		} else {
			if (infiniteCounter++ < 0) {
				dto.robots = new ArrayList<Robot>(actGen);
				Collections.copy(dto.robots, actGen);
				dto.livingRobots = dto.robots.size();
				dto.overagedRobots = overagedRobots;
				dto.starvedRobots = starvedRobots;
				dto.newChildren = newChildren;
				generations.add(dto);
			} else {
				popCount++;
				generations.get(infiniteCounter).livingRobots 
					= generations.get(infiniteCounter).livingRobots/popCount*(popCount-1) + actGen.size()/popCount;
				generations.get(infiniteCounter).overagedRobots 
					= generations.get(infiniteCounter).overagedRobots/popCount*(popCount-1) + overagedRobots/popCount;
				generations.get(infiniteCounter).starvedRobots 
					= generations.get(infiniteCounter).starvedRobots/popCount*(popCount-1) + starvedRobots/popCount;
				generations.get(infiniteCounter).newChildren 
					= generations.get(infiniteCounter).newChildren/popCount*(popCount-1) + newChildren/popCount;
			}
			
			infiniteCounter = infiniteCounter % (SimulationParameters.iterations - 1);
		}
	}

	public String showPopulation() {
		StringBuilder sb = new StringBuilder();
		Comparator<Robot> comp = new Comparator<Robot>() {
				public int compare(Robot r1, Robot r2) {
					if(r1.getReproductionFrequency() == r2.getReproductionFrequency()) {
						return (new Integer(r1.getFertility())).compareTo(r2.getFertility());
					}
					return (new Double(r1.getReproductionFrequency())).compareTo(r2.getReproductionFrequency());
				}};
		Collections.sort(getLastGeneration().robots, comp);
		Collections.reverse(getLastGeneration().robots);

		sb.append("The composite of the population looks as follows:\n");
		for (Robot r : getLastGeneration().robots) {
			sb.append(r.toString());
			sb.append("\n");
		}

		return sb.toString();
	}
	
	public GenerationDTO getLastGeneration() {
		return generations.get(generations.size() - 1);
	}

	public long getMaxPop() {
		return maxPop;
	}

	public int getMinPop() {
		return minPop;
	}
	
	public List<GenerationDTO> getGenerations() {
		return generations;
	}
}
